package org.spiderflow.common.context;

import org.spiderflow.common.concurrent.SubThreadPoolExecutor;
import org.spiderflow.common.model.SpiderNode;
import org.spiderflow.common.model.SpiderOutput;
import org.spiderflow.common.model.SpiderTask;
import org.spiderflow.common.enums.PauseEvent;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 爬虫上下文
 *
 * @author jmxd
 */
public class SpiderContext {
    private final Map<String, Object> map = new HashMap<>();
    private final String id = UUID.randomUUID().toString().replace("-", "");

    /**
     * 流程ID
     */
    private String flowId;

    /**
     * 流程执行线程
     */
    private SubThreadPoolExecutor threadPool;

    /**
     * 根节点
     */
    private SpiderNode rootNode;

    /**
     * 爬虫是否运行中
     */
    private volatile boolean running = true;

    /**
     * Future队列
     */
    private final LinkedBlockingQueue<Future<SpiderTask>> futureQueue = new LinkedBlockingQueue<>();

    /**
     * Cookie上下文
     */
    private final CookieContext cookieContext = new CookieContext();

    public List<SpiderOutput> getOutputs() {
        return Collections.emptyList();
    }

    public Object put(String key, Object value) {
        return map.put(key, value);
    }

    public <T> T get(String key) {
        return (T) map.get(key);
    }

    public <T> T get(String key, T defaultValue) {
        T value = this.get(key);
        return value == null ? defaultValue : value;
    }

    public String getFlowId() {
        return flowId;
    }

    public LinkedBlockingQueue<Future<SpiderTask>> getFutureQueue() {
        return futureQueue;
    }

    public void setFlowId(String flowId) {
        this.flowId = flowId;
    }

    public boolean isRunning() {
        return running;
    }

    public void setRunning(boolean running) {
        this.running = running;
    }

    public void addOutput(SpiderOutput output) {
        // Do nothing
    }

    public SubThreadPoolExecutor getThreadPool() {
        return threadPool;
    }

    public void setThreadPool(SubThreadPoolExecutor threadPool) {
        this.threadPool = threadPool;
    }

    public SpiderNode getRootNode() {
        return rootNode;
    }

    public void setRootNode(SpiderNode rootNode) {
        this.rootNode = rootNode;
    }

    public String getId() {
        return id;
    }

    public CookieContext getCookieContext() {
        return cookieContext;
    }

    public void pause(String nodeId, PauseEvent event, String key, Object value) {
        // Do nothing
    }

    public void resume() {
        // Do nothing
    }

    public void stop() {
        // Do nothing
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof SpiderContext)) {
            return false;
        }
        if (!super.equals(o)) {
            return false;
        }

        SpiderContext that = (SpiderContext) o;

        if (isRunning() != that.isRunning()) {
            return false;
        }
        if (!getId().equals(that.getId())) {
            return false;
        }
        if (!getFlowId().equals(that.getFlowId())) {
            return false;
        }
        if (!getThreadPool().equals(that.getThreadPool())) {
            return false;
        }
        if (!getRootNode().equals(that.getRootNode())) {
            return false;
        }
        if (!getFutureQueue().equals(that.getFutureQueue())) {
            return false;
        }
        return getCookieContext().equals(that.getCookieContext());
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + getId().hashCode();
        result = 31 * result + getFlowId().hashCode();
        result = 31 * result + getThreadPool().hashCode();
        result = 31 * result + getRootNode().hashCode();
        result = 31 * result + (isRunning() ? 1 : 0);
        result = 31 * result + getFutureQueue().hashCode();
        result = 31 * result + getCookieContext().hashCode();
        return result;
    }
}
